using SmartLink.Application.IServices;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SmartLink.DTOS;
using SmartLink.DTOS.SysBasic;
using AutoMapper;
using SmartLink.Domain.Entity;
using SmartLink.Domain.IServices;
using SmartLink.Infrastructure.Mappers;
using SmartLink.Domain.ExpandEntity;

namespace SmartLink.Application.Services
{
    public class SysModuleAppServices : ISysModuleAppServices
    {
        private ISysModuleServices _sysModuleServices;

        public SysModuleAppServices(ISysModuleServices sysModuleServices)
        {
            _sysModuleServices = sysModuleServices;
        }

        public Results AddModule(SysModuleDTO model)
        {
            var config = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<SysModuleDTO, SYS_Module>()
                    .ForMember(d => d.ID, opt => opt.Ignore());
            });
            IMapper mapper = config.CreateMapper();

            var module = mapper.Map<SYS_Module>(model);
            var opResult = _sysModuleServices.AddModule(module);
            return InfrastructureAppService.Transmit(opResult);
        }

        public Results DeleteModule(int id)
        {
            var opResult = _sysModuleServices.DeleteModule(id);
            return InfrastructureAppService.Transmit(opResult);
        }

        public Results<SysModuleDTO> GetModule(int id)
        {
            var entity = _sysModuleServices.GetModule(id);
            var model = Mapper.Map<SysModuleDTO>(entity);
            return InfrastructureAppService.Response(model);
        }

        public Results<IEnumerable<SysModuleDTO>> GetModuleChildren(int parentId)
        {
            var children = _sysModuleServices.GetModuleChildren(parentId);
            var models = Mapper.Map<IEnumerable<SysModuleDTO>>(children);
            return InfrastructureAppService.Response(models);
        }

        public Results<IList<SysModuleTreeNodeDTO>> GetModuleTree()
        {
            var entities = _sysModuleServices.GetAllModule();
            var tree = entities.ListToMultipleTree();
            return InfrastructureAppService.Response(tree);
        }

        public Results UpdateModule(SysModuleDTO model)
        {
            var module = Mapper.Map<SYS_Module>(model);
            var opResult = _sysModuleServices.UpdateModule(module);
            return InfrastructureAppService.Transmit(opResult);
        }

        public Results AddFunction(SysModuleFunctionDTO model)
        {
            var function = Mapper.Map<SYS_ModuleFunction>(model);
            var opResult = _sysModuleServices.AddFunction(function);
            return InfrastructureAppService.Transmit(opResult);
        }

        public Results UpdateFunction(SysModuleFunctionDTO model)
        {
            var function = Mapper.Map<SYS_ModuleFunction>(model);
            var opResult = _sysModuleServices.UpdateFunction(function);
            return InfrastructureAppService.Transmit(opResult);
        }

        public Results DeleteFunction(int id)
        {
            var opResult = _sysModuleServices.DeleteFunction(id);
            return InfrastructureAppService.Transmit(opResult);
        }

        public Results<SysModuleFunctionDTO> GetFunction(int id)
        {
            var entity = _sysModuleServices.GetFunction(id);
            var model = Mapper.Map<SysModuleFunctionDTO>(entity);
            return InfrastructureAppService.Response(model);
        }

        public Results<IEnumerable<SysModuleFunctionDTO>> GetModuleFunctions(string moduleCode)
        {
            var entities = _sysModuleServices.GetModuleFunctions(moduleCode);
            var models = Mapper.Map<IEnumerable<SysModuleFunctionDTO>>(entities);
            return InfrastructureAppService.Response(models);
        }

        public Results<IEnumerable<SysModuleFunctionTreeNodeDTO>> GetModuleFunctionTree()
        {
            var modules = _sysModuleServices.GetAllModule();
            var moduleTree = ConvertToSysModuleFunctionTreeNode(modules);
            var functions = _sysModuleServices.GetAllFunction();
            foreach (var moduleNode in moduleTree)
            {
                AppendFunctionNodes(moduleNode, functions);
            }
            return InfrastructureAppService.Response(moduleTree);
        }

        #region 私有方法

        private static IEnumerable<SysModuleFunctionTreeNodeDTO> ConvertToSysModuleFunctionTreeNode<TSource>(IEnumerable<TSource> entities) where TSource : SYS_Module
        {
            var roots = entities.Where(a => !a.ParentID.HasValue).OrderBy(a => a.Sort).ToList();
            var treeNodes = Mapper.Map<List<SysModuleFunctionTreeNodeDTO>>(roots);
            var nodeChildren = entities.Where(a => a.ParentID.HasValue).GroupBy(a => a.ParentID.Value)
                .ToDictionary(a => a.Key, a => Mapper.Map<List<SysModuleFunctionTreeNodeDTO>>(a.OrderBy(b => b.Sort).ToList()));

            foreach (var rootNode in treeNodes)
            {
                AppendSysModuleFunctionTreeChildNodes(rootNode, nodeChildren);
            }
            return treeNodes;
        }

        private static void AppendSysModuleFunctionTreeChildNodes(SysModuleFunctionTreeNodeDTO node, Dictionary<int, List<SysModuleFunctionTreeNodeDTO>> allChildNodes)
        {
            if (allChildNodes.ContainsKey(node.ModuleID))
            {
                node.Children = allChildNodes[node.ModuleID];
                foreach (var child in node.Children)
                {
                    AppendSysModuleFunctionTreeChildNodes(child, allChildNodes);
                }
            }
        }

        private static void AppendFunctionNodes(SysModuleFunctionTreeNodeDTO moduleNode, IEnumerable<SYS_ModuleFunction> functions)
        {
            var moduleFunctions = functions.Where(a => a.ModuleCode == moduleNode.Code).OrderBy(a => a.Sort).ToList();
            moduleNode.Functions = Mapper.Map<IList<SysModuleFunctionNodeDTO>>(moduleFunctions);
            if (moduleNode.Children != null && moduleNode.Children.Count > 0)
            {
                foreach (var node in moduleNode.Children)
                {
                    AppendFunctionNodes(node, functions);
                }
            }
        }
        private static void ModuleTreeRecursion(SysModuleFunctionTreeNodeDTO moduleNode, ref IList<SysModuleWithFunctionsListItemDTO> list)
        {
            var listItem = Mapper.Map<SysModuleWithFunctionsListItemDTO>(moduleNode);
            list.Add(listItem);
            if (moduleNode.Children != null && moduleNode.Children.Count > 0)
            {
                foreach (var node in moduleNode.Children)
                {
                    ModuleTreeRecursion(node, ref list);
                }
            }
        }

        #endregion

        public Results<IList<SysModuleWithFunctionsListItemDTO>> GetModuleAndFunctionsList()
        {
            var modules = _sysModuleServices.GetAllWithRelation();
            var functions = _sysModuleServices.GetAllFunction();
            var result = ConvertToModuleAndFunctionsList(modules, functions);
            return InfrastructureAppService.Response(result);
        }

        public static IList<SysModuleWithFunctionsListItemDTO> ConvertToModuleAndFunctionsList(IEnumerable<SysModuleExpand> modules, IEnumerable<SYS_ModuleFunction> functions)
        {
            var moduleTreeNodes = ConvertToSysModuleFunctionTreeNode(modules);
            foreach (var moduleNode in moduleTreeNodes)
            {
                AppendFunctionNodes(moduleNode, functions);
            }

            IList<SysModuleWithFunctionsListItemDTO> list = new List<SysModuleWithFunctionsListItemDTO>();
            foreach (var node in moduleTreeNodes)
            {
                ModuleTreeRecursion(node, ref list);
            }
            return list;
        }
    }
}
